\subsection{讀、寫以及拷貝緩衝對象}

\topclfunc{clEnqueueReadBuffer}

\topclfunc{clEnqueueWriteBuffer}

\startCLFUNC
cl_int clEnqueueReadBuffer(
			cl_command_queue command_queue,
			cl_mem buffer,
			cl_bool blocking_read,
			size_t offset,
			size_t cb,
			void *ptr,
			cl_uint num_events_in_wait_list,
			const cl_event *event_wait_list,
			cl_event *event)

cl_int clEnqueueWriteBuffer(
			cl_command_queue command_queue,
			cl_mem buffer,
			cl_bool blocking_write,
			size_t offset,
			size_t cb,
			const void *ptr,
			cl_uint num_events_in_wait_list,
			const cl_event *event_wait_list,
			cl_event *event)
\stopCLFUNC

這兩個函式會將一個用於讀寫\cnglo{bufobj}的\cnglo{cmd}入隊，
此\cnglo{cmd}可以將\cnglo{bufobj}的內容讀到\cnglo{host}內存中，
或者由\cnglo{host}內存寫入到\cnglo{bufobj}中。

\carg{command_queue} 就是\cnglo{cmd}要進入的隊列。
\carg{command_queue} 和 \carg{buffer} 必須是由同一個 OpenCL \cnglo{context}創建的。

\carg{buffer} 是一個 \cnglo{bufobj}。

\carg{blocking_read} 和 \carg{blocking_write}
表明讀寫操作是{\ftRef{阻塞}}的還是{\ftRef{非阻塞}}的。

如果 \carg{blocking_read} 是 \cenum{CL_TRUE}，即讀\cnglo{cmd}是阻塞的，
直到 \carg{buffer} 中的數據完全拷貝到 \carg{ptr} 所指內存中後，
\capi{clEnqueueReadBuffer} 才會返回。

如果 \carg{blocking_read} 是 \cenum{CL_FALSE}，即讀\cnglo{cmd}是非阻塞的，
\capi{clEnqueueReadBuffer} 將此\cnglo{cmd}入隊後就會返回。
只有等到讀\cnglo{cmd}執行完畢，才能繼續使用 \carg{ptr} 所指向的內容。
參數 \carg{event} 會返回一個\cnglo{evtobj}，可用來查詢讀\cnglo{cmd}的執行情況。
讀\cnglo{cmd}完成後，\cnglo{app}就可以繼續使用 \carg{ptr} 所指向的內容了。

如果 \carg{blocking_write} 是 \cenum{CL_TRUE}，
OpenCL 實作會拷貝 \carg{ptr} 所指向的數據，並將一個寫\cnglo{cmd}入隊。
當 \capi{clEnqueueWriteBuffer} 返回後，
\cnglo{app}就可以繼續使用 \carg{ptr} 所指向的內存了。

如果 \carg{blocking_write} 是 \cenum{CL_FALSE}，
OpenCL 實作會用 \carg{ptr} 實施非阻塞的寫操作。
既然非阻塞，實作就可以立即返回。返回後，\cnglo{app}還不能立刻就使用 \carg{ptr} 所指內存。
參數 \carg{event} 會返回一個\cnglo{evtobj}，可用來查詢寫\cnglo{cmd}的執行情況。
寫\cnglo{cmd}完成後，\cnglo{app}就可以重用 \carg{ptr} 所指向的內存了。

\carg{offset} 是讀寫區域在\cnglo{bufobj}中的偏移量，單位字節。

\carg{cb} 是要讀寫數據的大小，單位字節。

\carg{ptr} 指向\cnglo{host}中的一塊內存，
用作讀\cnglo{cmd}的數據源以及寫\cnglo{cmd}的目的地。

\carg{event_wait_list} 和 \carg{num_events_in_wait_list} 中
列出了執行此\cnglo{cmd}前要等待的事件。
如果 \carg{event_wait_list} 是 \cmacro{NULL}，則無須等待任何事件，
並且 \carg{num_events_in_wait_list} 必須是 0。
如果 \carg{event_wait_list} 不是 \cmacro{NULL}，則其中所有事件都必須是有效的，
並且 \carg{num_events_in_wait_list} 必須大於 0。
\carg{event_wait_list} 中的事件充當同步點，
並且必須與 \carg{command_queue} 位於同一個\cnglo{context}中。
此函式返回後，就可以回收並重用 \carg{event_wait_list} 所關聯的內存了。

\carg{event} 會返回一個\cnglo{evtobj}，
用來識別此讀、寫\cnglo{cmd}，可用來查詢或等待此\cnglo{cmd}完成。
而如果 \carg{event} 是 \cmacro{NULL}，就沒辦法查詢此\cnglo{cmd}的狀態或等待其完成了。
如果 \carg{event_wait_list} 和 \carg{event} 都不是 \cmacro{NULL}，
\carg{event} 不能屬於 \carg{event_wait_list}。

如果執行成功，
\capi{clEnqueueReadBuffer} 和 \capi{clEnqueueWriteBuffer} 會返回 \cenum{CL_SUCCESS}。
否則，返回下列錯誤碼之一：
\startigBase
\item \cenum{CL_INVALID_COMMAND_QUEUE}，如果 \carg{command_queue} 無效。

\item \cenum{CL_INVALID_CONTEXT}，
如果 \carg{command_queue} 和 \carg{buffer} 位於不同的\cnglo{context}中，
或者 \carg{command_queue} 和 \carg{event_wait_list} 中的事件位於不同的\cnglo{context}中。

\item \cenum{CL_INVALID_MEM_OBJECT}，如果 \carg{buffer} 無效。

\item \cenum{CL_INVALID_VALUE}，如果 \math{(\marg{offset}, \marg{size})} 所指定的區域越限，
或者 \carg{ptr} 是 \cmacro{NULL}，或者 \carg{size} 是 0。

\startitem
\cenum{CL_INVALID_EVENT_WAIT_LIST}，如果滿足下列條件中的任一項：
\startigBase
\item \carg{event_wait_list} 是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} > 0；
\item 或者 \carg{event_wait_list} 不是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} 是 0；
\item 或者 \carg{event_wait_list} 中有無效的事件。
\stopigBase
\stopitem

\item \cenum{CL_MISALIGNED_SUB_BUFFER_OFFSET}，
如果 \carg{buffer} 是子\cnglo{bufobj}，
且創建此對象時所指定的 \carg{offset} 沒有
與 \carg{queue} 所關聯\cnglo{device}的 \cenum{CL_DEVICE_MEM_BASE_ADDR_ALIGN} 對齊。

\item \cenum{CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST}，
如果讀寫操作是阻塞的，且 \carg{event_wait_list} 中任一命令的執行狀態是負整數。

\item \cenum{CL_MEM_OBJECT_ALLOCATION_FAILURE}，如果為 \carg{buffer} 分配內存失敗。

\item \cenum{CL_INVALID_OPERATION}，如果調用的是 \capi{clEnqueueReadBuffer}，
但創建 \carg{buffer} 時指定了 \cenum{CL_MEM_HOST_WRITE_ONLY} 或 \cenum{CL_MEM_HOST_NO_ACCESS}。

\item \cenum{CL_INVALID_OPERATION}，如果調用的是 \capi{clEnqueueWriteBuffer}，
但創建 \carg{buffer} 時指定了 \cenum{CL_MEM_HOST_READ_ONLY} 或 \cenum{CL_MEM_HOST_NO_ACCESS}。

\item \cenum{CL_OUT_OF_RESOURCES}，如果\scdevfailres。
\item \cenum{CL_OUT_OF_HOST_MEMORY}，如果\schostfailres。
\stopigBase

\topclfunc{clEnqueueReadBufferRect}

\topclfunc{clEnqueueWriteBufferRect}

\startCLFUNC
cl_int clEnqueueReadBufferRect (
			cl_command_queue command_queue,
			cl_mem buffer,
			cl_bool blocking_read,
			const size_t *buffer_origin,
			const size_t *host_origin,
			const size_t *region,
			size_t buffer_row_pitch,
			size_t buffer_slice_pitch,
			size_t host_row_pitch,
			size_t host_slice_pitch,
			void *ptr,
			cl_uint num_events_in_wait_list,
			const cl_event *event_wait_list,
			cl_event *event)

cl_int clEnqueueWriteBufferRect (
			cl_command_queue command_queue,
			cl_mem buffer,
			cl_bool blocking_write,
			const size_t *buffer_origin,
			const size_t *host_origin,
			const size_t *region,
			size_t buffer_row_pitch,
			size_t buffer_slice_pitch,
			size_t host_row_pitch,
			size_t host_slice_pitch,
			const void *ptr,
			cl_uint num_events_in_wait_list,
			const cl_event *event_wait_list,
			cl_event *event)
\stopCLFUNC

這兩個函式所入隊的命令可以讀寫\cnglo{bufobj}中 2D 或 3D 矩形區域。

\carg{command_queue} 就是\cnglo{cmd}要進入的隊列。
\carg{command_queue} 和 \carg{buffer} 必須是由同一個 OpenCL \cnglo{context}創建的。

\carg{buffer} 是一個 \cnglo{bufobj}。

\carg{blocking_read} 和 \carg{blocking_write}
表明讀寫操作是{\ftRef{阻塞}}的還是{\ftRef{非阻塞}}的。

如果 \carg{blocking_read} 是 \cenum{CL_TRUE}，即讀\cnglo{cmd}是阻塞的，
直到 \carg{buffer} 中的數據完全拷貝到 \carg{ptr} 所指內存中後，
\capi{clEnqueueReadBufferRect} 才會返回。

如果 \carg{blocking_read} 是 \cenum{CL_FALSE}，即讀\cnglo{cmd}是非阻塞的，
\capi{clEnqueueReadBufferRect} 將此\cnglo{cmd}入隊後就會返回。
只有等到讀\cnglo{cmd}執行完畢，才能繼續使用 \carg{ptr} 所指向的內容。
參數 \carg{event} 會返回一個\cnglo{evtobj}，可用來查詢讀\cnglo{cmd}的執行情況。
讀\cnglo{cmd}完成後，\cnglo{app}就可以繼續使用 \carg{ptr} 所指向的內容了。

如果 \carg{blocking_write} 是 \cenum{CL_TRUE}，
OpenCL 實作會拷貝 \carg{ptr} 所指向的數據，並將一個寫\cnglo{cmd}入隊。
當 \capi{clEnqueueWriteBufferRect} 返回後，
\cnglo{app}就可以繼續使用 \carg{ptr} 所指向的內存了。

如果 \carg{blocking_write} 是 \cenum{CL_FALSE}，
OpenCL 實作會用 \carg{ptr} 實施非阻塞的寫操作。
既然非阻塞，實作就可以立即返回。返回後，\cnglo{app}還不能立刻就使用 \carg{ptr} 所指內存。
參數 \carg{event} 會返回一個\cnglo{evtobj}，可用來查詢寫\cnglo{cmd}的執行情況。
寫\cnglo{cmd}完成後，\cnglo{app}就可以重用 \carg{ptr} 所指向的內存了。

\carg{buffer_origin} 定義了要讀寫的內存區域在 \carg{buffer} 中的偏移量 \math{(x,y,z)}。
對於 2D 矩形區域，\math{z} 的值即 \math{\marg{buffer_origin}[2]} 應該是 0。
偏移量這樣計算：
\startformula \startalign
 \NC  \NC \marg{buffer_origin}[2] * \marg{buffer_slice_pitch} \NR
 \NC + \NC \marg{buffer_origin}[1] * \marg{buffer_row_pitch} \NR
 \NC + \NC \marg{buffer_origin}[0] \NR
\stopalign \stopformula

\carg{host_origin} 定義了要讀寫的內存區域在 \carg{ptr} 中的偏移量 \math{(x,y,z)}。
對於 2D 矩形區域，\math{z} 的值即 \math{\marg{host_origin}[2]} 應該是 0。
偏移量這樣計算：
\startformula \startalign
 \NC  \NC \marg{host_origin}[2] * \marg{host_slice_pitch} \NR
 \NC + \NC \marg{host_origin}[1] * \marg{host_row_pitch} \NR
 \NC + \NC \marg{host_origin}[0] \NR
\stopalign \stopformula

\carg{region} 定義了要讀寫的 2D 或 3D 區域：\math{(width, height, depth)}，
其單位分別是 byte、 row、 slice。
對於 2D 區域， \math{depth} 的值，即 \math{\marg{region}[2]} 應該是 1。
\carg{region} 中的值不能为 0。

\carg{buffer_row_pitch} 是 \carg{buffer} 中每一行數據的字節數。
如果 \carg{buffer_row_pitch} 是 0，則在計算偏移量時用 \math{\marg{region}[0]} 替代。

\carg{buffer_slice_pitch} 是 \carg{buffer} 中每個 2D 平面（slice）的字節數。
如果 \carg{buffer_slice_pitch} 是 0，
則在計算偏移量時用 \math{\marg{region}[1] * \marg{buffer_row_pitch}} 替代。

\carg{host_row_pitch} 是 \carg{ptr} 中每一行數據的字節數。
如果 \carg{host_row_pitch} 是 0，則在計算偏移量時用 \math{\marg{region}[0]} 替代。

\carg{host_slice_pitch} 是 \carg{ptr} 中每個 2D 平面（slice）的字節數。
如果 \carg{host_slice_pitch} 是 0，
則在計算偏移量時用 \math{\marg{region}[1] * \marg{host_row_pitch}} 替代。

\carg{ptr} 指向\cnglo{host}中的一塊內存，
用作讀\cnglo{cmd}的數據源以及寫\cnglo{cmd}的目的地。

\carg{event_wait_list} 和 \carg{num_events_in_wait_list}
中列出了執行此\cnglo{cmd}前要等待的事件。
如果 \carg{event_wait_list} 是 \cmacro{NULL}，
則無須等待任何事件，並且 \carg{num_events_in_wait_list} 必須是 0。
如果 \carg{event_wait_list} 不是 \cmacro{NULL}，
則其中所有事件都必須是有效的，並且 \carg{num_events_in_wait_list} 必須大於 0。
\carg{event_wait_list} 中的事件充當同步點，
並且必須與 \carg{command_queue} 位於同一個\cnglo{context}中。
此函式返回後，就可以回收並重用 \carg{event_wait_list} 所關聯的內存了。

\carg{event} 會返回一個\cnglo{evtobj}，
用來識別此讀、寫\cnglo{cmd}，可用來查詢或等待此\cnglo{cmd}完成。
而如果 \carg{event} 是 \cmacro{NULL}，就沒辦法查詢此\cnglo{cmd}的狀態或等待其完成了。
如果 \carg{event_wait_list} 和 \carg{event} 都不是 \cmacro{NULL}，
\carg{event} 不能屬於 \carg{event_wait_list}。

如果執行成功， \capi{clEnqueueReadBufferRect} 和 \capi{clEnqueueWriteBufferRect}
會返回 \cenum{CL_SUCCESS}。
否則，返回下列錯誤碼之一：
\startigBase
\item \cenum{CL_INVALID_COMMAND_QUEUE}，如果 \carg{command_queue} 無效。

\item \cenum{CL_INVALID_CONTEXT}，
如果 \carg{command_queue} 和 \carg{buffer} 位於不同的\cnglo{context}中，
或者 \carg{command_queue} 和 \carg{event_wait_list} 中的事件位於不同的\cnglo{context}中。

\item \cenum{CL_INVALID_MEM_OBJECT}，如果 \carg{buffer} 無效。

\item \cenum{CL_INVALID_VALUE}，
如果下列區域越限：
\startformula
(\marg{buffer_origin}, \marg{region}, \marg{buffer_row_pitch}, \marg{buffer_slice_pitch})
\stopformula

\item \cenum{CL_INVALID_VALUE}，如果 \carg{ptr} 是 \cmacro{NULL}。

\item \cenum{CL_INVALID_VALUE}，如果 \carg{region} 中的任何元素是 0。

\item \cenum{CL_INVALID_VALUE}，
如果 \carg{buffer_row_pitch} 不是 0 且小於 \math{\marg{region}[0]}。

\item \cenum{CL_INVALID_VALUE}，
如果 \carg{host_row_pitch} 不是 0 且小於 \math{\marg{region}[0]}。

\startitem
\cenum{CL_INVALID_VALUE}，如果 \carg{buffer_slice_pitch} 滿足下列所有條件：
\startigBase
\item 不是 0、
\item 小於 \math{\marg{region}[1] * \marg{buffer_row_pitch}}、
\item 且不是 \carg{buffer_row_pitch} 的整數倍。
\stopigBase
\stopitem

\startitem
\cenum{CL_INVALID_VALUE}，如果 \carg{host_slice_pitch} 滿足下列條件：
\startigBase
\item 不是 0、
\item 小於 \math{\marg{region}[1] * \marg{host_row_pitch}}、
\item 且不是 \carg{host_row_pitch} 的整數倍。
\stopigBase
\stopitem

\startitem
\cenum{CL_INVALID_EVENT_WAIT_LIST}，如果滿足下列條件中的任一項：
\startigBase
\item \carg{event_wait_list} 是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} > 0；
\item 或者 \carg{event_wait_list} 不是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} 是 0；
\item 或者 \carg{event_wait_list} 中有無效的事件。
\stopigBase
\stopitem

\item \cenum{CL_MISALIGNED_SUB_BUFFER_OFFSET}，
如果 \carg{buffer} 是子\cnglo{bufobj}，
且創建此對象時所指定的 \carg{offset} 沒有與 \carg{command_queue} 所關聯\cnglo{device}
的 \cenum{CL_DEVICE_MEM_BASE_ADDR_ALIGN} 對齊。

\item \cenum{CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST}，
如果讀寫操作是阻塞的，且 \carg{event_wait_list} 中任何命令的執行狀態是負整數。

\item \cenum{CL_MEM_OBJECT_ALLOCATION_FAILURE}，如果為 \carg{buffer} 分配內存失敗。

\item \cenum{CL_INVALID_OPERATION}，如果調用的是 \capi{clEnqueueReadBufferRect}，
但創建 \carg{buffer} 時指定了
\cenum{CL_MEM_HOST_WRITE_ONLY} 或 \cenum{CL_MEM_HOST_NO_ACCESS}。

\item \cenum{CL_INVALID_OPERATION}，如果調用的是 \capi{clEnqueueWriteBufferRect}，
但創建 \carg{buffer} 時指定了
\cenum{CL_MEM_HOST_READ_ONLY} 或 \cenum{CL_MEM_HOST_NO_ACCESS}。

\item \cenum{CL_OUT_OF_RESOURCES}，如果\scdevfailres。
\item \cenum{CL_OUT_OF_HOST_MEMORY}，如果\schostfailres。
\stopigBase

\startnotepar% start notepar
如果調用 \capi{clEnqueueReadBuffer} 時將引數 \carg{ptr} 設置為 \math{\marg{host_ptr} + \marg{offset}}
（其中 \carg{host_ptr} 是用 \cenum{CL_MEM_USE_HOST_PTR} 創建所要讀取的\cnglo{bufobj}時指定的），
為避免\cnglo{undef}的行為，必須滿足下列要求：
\startigBase
\item 在讀\cnglo{cmd}開始執行前，
所有使用此\cnglo{bufobj}
（或由此\cnglo{bufobj}創建的\cnglo{memobj}，包括\cnglo{bufobj}和\cnglo{imgobj}）
的\cnglo{cmd}都已經執行完畢。

\item 所有用此\cnglo{bufobj}創建的\cnglo{bufobj}或\cnglo{imgobj}都沒有被映射。

\item 在讀\cnglo{cmd}執行完之前，
所有用此\cnglo{bufobj}創建的\cnglo{bufobj}或\cnglo{imgobj}都沒有被任何\cnglo{cmdq}使用。
\stopigBase

如果調用 \capi{clEnqueueReadBufferRect} 時將引數 \carg{ptr} 設置為 \carg{host_ptr}，
並且 \carg{host_origin} 和 \carg{buffer_origin} 相同，
其中 \carg{host_ptr} 就是用 \cenum{CL_MEM_USE_HOST_PTR} 創建所要讀取的\cnglo{bufobj}時指定的，
要滿足的要求跟 \capi{clEnqueueReadBuffer} 一樣。

如果調用 \capi{clEnqueueWriteBuffer} 時將引數 \carg{ptr} 置為 \math{\marg{host_ptr} + \marg{offset}}，
其中 \carg{host_ptr} 就是用 \cenum{CL_MEM_USE_HOST_PTR} 創建所要寫入的\cnglo{bufobj}時指定的，
為避免未定義的行為，必須滿足下列要求：
\startigBase
\item 在寫\cnglo{cmd}開始執行前，
\math{(\marg{host_ptr} + \marg{offset}, \marg{cb})} 所劃定的\cnglo{host}\cnglo{memregion}必須含有最新的數據。

\item 所有用此\cnglo{bufobj}創建的\cnglo{bufobj}或\cnglo{imgobj}都沒有被映射。

\item 在寫\cnglo{cmd}執行完之前，
所有用此\cnglo{bufobj}創建的\cnglo{bufobj}或\cnglo{imgobj}都沒有被任何\cnglo{cmdq}使用。
\stopigBase

如果調用 \capi{clEnqueueWriteBufferRect} 時將引數 \carg{ptr} 設置為 \carg{host_ptr}，
並且 \carg{host_origin} 和 \carg{buffer_origin} 相同，
其中 \carg{host_ptr} 就是用 \cenum{CL_MEM_USE_HOST_PTR} 創建所要讀取的\cnglo{bufobj}時指定的，
為避免\cnglo{undef}的行為，必須滿足下列要求：
\startigBase
\item 在寫\cnglo{cmd}開始執行前，
\math{(\marg{buffer_origin}, \marg{region})} 所劃定的\cnglo{host}\cnglo{memregion}必須含有最新的數據。

\item 所有用此\cnglo{bufobj}創建的\cnglo{bufobj}或\cnglo{imgobj}都沒有被映射。

\item 在寫\cnglo{cmd}執行完之前，
所有用此\cnglo{bufobj}創建的\cnglo{bufobj}或\cnglo{imgobj}都沒有被任何\cnglo{cmdq}使用。
\stopigBase
\stopnotepar% stop notepar

\topclfunc{clEnqueueCopyBuffer}

\startCLFUNC
cl_int clEnqueueCopyBuffer (
			cl_command_queue command_queue,
			cl_mem src_buffer,
			cl_mem dst_buffer,
			size_t src_offset,
			size_t dst_offset,
			size_t size,
			cl_uint num_events_in_wait_list,
			const cl_event *event_wait_list,
			cl_event *event)
\stopCLFUNC

此函式會將一個拷貝\cnglo{cmd}入隊，
此\cnglo{cmd}會將\cnglo{bufobj} \carg{src_buffer} 的內容拷貝到 \carg{dst_buffer} 中。

\carg{command_queue} 即拷貝\cnglo{cmd}所要插入的\cnglo{cmdq}。
\carg{command_queue}、 \carg{src_buffer} 和 \carg{dst_buffer}
必須位於同一 OpenCL \cnglo{context}中。

\carg{src_offset} 即在 \carg{src_buffer} 中的什麼位置開始讀取數據。

\carg{dst_offset} 即在 \carg{dst_buffer} 中的什麼位置開始寫入數據。

\carg{size} 即所要拷貝數據的字節數。

\carg{event_wait_list} 和 \carg{num_events_in_wait_list} 中
列出了執行此\cnglo{cmd}前要等待的事件。
如果 \carg{event_wait_list} 是 \cmacro{NULL}，
則無須等待任何事件，並且 \carg{num_events_in_wait_list} 必須是 0。
如果 \carg{event_wait_list} 不是 \cmacro{NULL}，
則其中所有事件都必須是有效的，並且 \carg{num_events_in_wait_list} 必須大於 0。
\carg{event_wait_list} 中的事件充當同步點，
並且必須與 \carg{command_queue} 位於同一個\cnglo{context}中。
此函式返回後，就可以回收並重用 \carg{event_wait_list} 所關聯的內存了。

\carg{event} 會返回一個\cnglo{evtobj}，
用來識別此拷貝\cnglo{cmd}，可用來查詢或等待此\cnglo{cmd}完成。
而如果 \carg{event} 是 \cmacro{NULL}，就沒辦法查詢此\cnglo{cmd}的狀態或等待其完成了。
不過可以用 \capi{clEnqueueBarrierWithWaitList} 來代替。
如果 \carg{event_wait_list} 和 \carg{event} 都不是 \cmacro{NULL}，
則 \carg{event} 不能屬於 \carg{event_wait_list}。

如果執行成功， \capi{clEnqueueCopyBuffer} 會返回 \cenum{CL_SUCCESS}。
否則，返回下列錯誤碼之一：
\startigBase
\item \cenum{CL_INVALID_COMMAND_QUEUE}，如果 \carg{command_queue} 無效。

\item \cenum{CL_INVALID_CONTEXT}，
如果 \carg{command_queue}、 \carg{src_buffer} 以及 \carg{dst_buffer}
位於不同的\cnglo{context}中，
或者 \carg{command_queue} 和 \carg{event_wait_list} 中的事件
位於不同的\cnglo{context}中。

\item \cenum{CL_INVALID_MEM_OBJECT}，
如果 \carg{src_buffer} 或 \carg{dst_buffer} 無效。

\item \cenum{CL_INVALID_VALUE}，
如果 \carg{src_offset}、 \carg{dst_offset}、 \carg{size}、
\math{\marg{src_offset} + \marg{size}} 或 \math{\marg{dst_offset} + \marg{size}} 越限。

\item \cenum{CL_INVALID_VALUE}，如果 \carg{size} 是 0。

\startitem
\cenum{CL_INVALID_EVENT_WAIT_LIST}，如果滿足下列條件中的任一項：
\startigBase
\item \carg{event_wait_list} 是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} > 0；
\item 或者 \carg{event_wait_list} 不是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} 是 0；
\item 或者 \carg{event_wait_list} 中有無效的事件。
\stopigBase
\stopitem

\item \cenum{CL_MISALIGNED_SUB_BUFFER_OFFSET}，
如果 \carg{src_buffer} 是子\cnglo{bufobj}，
且創建此對象時所指定的 \carg{offset} 沒有與 \carg{command_queue} 所關聯\cnglo{device}
的 \cenum{CL_DEVICE_MEM_BASE_ADDR_ALIGN} 對齊。

\item \cenum{CL_MISALIGNED_SUB_BUFFER_OFFSET}，
如果 \carg{dst_buffer} 是子\cnglo{bufobj}，
且創建此對象時所指定的 \carg{offset} 沒有與 \carg{command_queue} 所關聯\cnglo{device}
的 \cenum{CL_DEVICE_MEM_BASE_ADDR_ALIGN} 對齊。

\item \cenum{CL_MEM_COPY_OVERLAP}，
如果 \carg{src_buffer} 和 \carg{dst_buffer} 是同一個\cnglo{bufobj}或子\cnglo{bufobj}，
且源和目的區域重疊。
或者 \carg{src_buffer} 和 \carg{dst_buffer} 是同一\cnglo{bufobj}的不同子\cnglo{bufobj}，
且他們重疊。
當 \math{\marg{src_offset} \leq \marg{dst_offset} \leq \marg{src_offset} + \marg{size} - 1} 或
\math{\marg{dst_offset} \leq \marg{src_offset} \leq \marg{dst_offset} + \marg{size} - 1} 時就認為重疊了。

\item \cenum{CL_MEM_OBJECT_ALLOCATION_FAILURE}，
如果為 \carg{src_buffer} 或 \carg{dst_buffer} 分配內存失敗。

\item \cenum{CL_INVALID_OPERATION}，如果調用的是 \capi{clEnqueueReadBufferRect}，
但創建 \carg{buffer} 時指定了 \cenum{CL_MEM_HOST_WRITE_ONLY} 或 \cenum{CL_MEM_HOST_NO_ACCESS}。

\item \cenum{CL_INVALID_OPERATION}，如果調用的是 \capi{clEnqueueWriteBufferRect}，
但創建 \carg{buffer} 時指定了 \cenum{CL_MEM_HOST_READ_ONLY} 或 \cenum{CL_MEM_HOST_NO_ACCESS}。

\item \cenum{CL_OUT_OF_RESOURCES}，如果\scdevfailres。
\item \cenum{CL_OUT_OF_HOST_MEMORY}，如果\schostfailres。
\stopigBase

\topclfunc{clEnqueueCopyBufferRect}

\startCLFUNC
cl_int clEnqueueCopyBufferRect (
			cl_command_queue command_queue,
			cl_mem src_buffer,
			cl_mem dst_buffer,
			const size_t *src_origin,
			const size_t *dst_origin,
			const size_t *region,
			size_t src_row_pitch,
			size_t src_slice_pitch,
			size_t dst_row_pitch,
			size_t dst_slice_pitch,
			cl_uint num_events_in_wait_list,
			const cl_event *event_wait_list,
			cl_event *event)
\stopCLFUNC

此函式會將一個拷貝\cnglo{cmd}入隊，
此\cnglo{cmd}會將\cnglo{bufobj} \carg{src_buffer} 的一個 2D 或 3D 矩形區域
拷貝到 \carg{dst_buffer} 中。
拷貝時源和宿的偏移量的計算方式在後面 \carg{src_origin} 和 \carg{dst_origin} 的描述中會涉及。
每次拷貝的字節數等於區域寬度，然後源和宿的偏移量會增加相應的行間距（row pitch）。
每拷貝完一個 2D 矩形，源和宿的偏移量會增加相應的面間距（slice pitch）。

\startnotepar
如果 \carg{src_buffer} 和 \carg{dst_buffer} 是同一個\cnglo{bufobj}，
\carg{src_row_pitch} 和 \carg{dst_row_pitch} 必須相同，
\carg{src_slice_pitch} 和 \carg{dst_slice_pitch} 也必須相同。
\stopnotepar

\carg{command_queue} 就是拷貝\cnglo{cmd}要進入的隊列。
\carg{command_queue}、 \carg{src_buffer}、 \carg{dst_buffer}
必須位於同一 OpenCL \cnglo{context}中。

\carg{src_origin} 定義了 \carg{src_buffer} 中內存區域的偏移量 \math{(x,y,z)}。
對於 2D 矩形區域， \math{z} 的值即 \math{\marg{src_origin}[2]} 應該是 0。
偏移量這樣計算：
\math{\marg{src_origin}[2] * \marg{src_slice_pitch} + \marg{src_origin}[1] * \marg{src_row_pitch} + \marg{src_origin}[0]}。

\carg{dst_origin} 定義了 \carg{dst_buffer} 中內存區域的偏移量 \math{(x,y,z)}。
對於 2D 矩形區域， \math{z} 的值即 \math{\marg{dst_origin}[2]} 應該是 0。
偏移量這樣計算：
\math{\marg{dst_origin}[2] * \marg{dst_slice_pitch} + \marg{dst_origin}[1] * \marg{dst_row_pitch} + \marg{dst_origin}[0]}。

\carg{region} 定義了要拷貝的 2D 或 3D 區域： \math{(width,height,depth)}，
其單位分別是 byte、 row、 slice。
對於 2D 區域， \math{depth} 的值，即 \math{\marg{region}[2]} 應該是 1。
\carg{region} 中的值不能为 0。

\carg{src_row_pitch} 是 \carg{src_buffer} 中每一行數據的字節數。
如果 \carg{src_row_pitch} 是 0，則在計算偏移量時用 \math{\marg{region}[0]} 替代。

\carg{src_slice_pitch} 是 \carg{src_buffer} 中每個 2D 平面（slice）的字節數。
如果 \carg{src_slice_pitch} 是 0，
則在計算偏移量時用 \math{\marg{region}[1] * \marg{src_row_pitch}} 替代。

\carg{dst_row_pitch} 是 \carg{dst_buffer} 中每一行數據的字節數。
如果 \carg{dst_row_pitch} 是 0，則在計算偏移量時用 \math{\marg{region}[0]} 替代。

\carg{dst_slice_pitch} 是 \carg{dst_buffer} 中每個 2D 平面的字節數。
如果 \carg{dst_slice_pitch} 是 0，
則在計算偏移量時用 \math{\marg{region}[1] * \marg{src_row_pitch}} 替代。

\carg{event_wait_list} 和 \carg{num_events_in_wait_list}
中列出了執行此\cnglo{cmd}前要等待的事件。
如果 \carg{event_wait_list} 是 \cmacro{NULL}，
則無須等待任何事件，並且 \carg{num_events_in_wait_list} 必須是0。
如果 \carg{event_wait_list} 不是 \cmacro{NULL}，
則其中所有事件都必須是有效的，並且 \carg{num_events_in_wait_list} 必須大於 0。
\carg{event_wait_list} 中的事件充當同步點，
並且必須與 \carg{command_queue} 位於同一個\cnglo{context}中。
此函式返回後，就可以回收並重用 \carg{event_wait_list} 所關聯的內存了。

\carg{event} 會返回一個\cnglo{evtobj}，
用來識別此讀、寫\cnglo{cmd}，可用來查詢或等待此\cnglo{cmd}完成。
而如果 \carg{event} 是 \cmacro{NULL}，就沒辦法查詢此\cnglo{cmd}的狀態或等待其完成了。
這時可以用 \capi{clEnqueueBarrierWithWaitList} 來代替。
如果 \carg{event_wait_list} 和 \carg{event} 都不是 \cmacro{NULL}，
\carg{event} 不能屬於 \carg{event_wait_list}。

如果執行成功， \capi{clEnqueueCopyBufferRect} 會返回 \cenum{CL_SUCCESS}。
否則，返回下列錯誤碼之一：
\startigBase
\item \cenum{CL_INVALID_COMMAND_QUEUE}，如果 \carg{command_queue} 無效。

\item \cenum{CL_INVALID_CONTEXT}，
如果 \carg{command_queue}、 \carg{src_buffer} 和 \carg{dst_buffer}
位於不同的\cnglo{context}中，
或者 \carg{command_queue} 和 \carg{event_wait_list} 中的事件
位於不同的\cnglo{context}中。

\item \cenum{CL_INVALID_MEM_OBJECT}，
如果 \carg{src_buffer} 或 \carg{dst_buffer} 無效。

\startitem
\cenum{CL_INVALID_VALUE}，如果下列兩個區域中任意一個越限：
\startigBase
\item \math{(\marg{src_origin}, \marg{region}, \marg{src_row_pitch}, \marg{src_slice_pitch})}
\item \math{(\marg{dst_origin}, \marg{region}, \marg{dst_row_pitch}, \marg{dst_slice_pitch})}
\stopigBase
\stopitem

\item \cenum{CL_INVALID_VALUE}，如果 \carg{region} 中的任何元素是 0。

\item \cenum{CL_INVALID_VALUE}，如果 \carg{src_row_pitch} 不是 0 且小於 \math{\marg{region}[0]}。

\item \cenum{CL_INVALID_VALUE}，如果 \carg{dst_row_pitch} 不是 0 且小於 \math{\marg{region}[0]}。

\startitem
\cenum{CL_INVALID_VALUE}，如果 \carg{src_slice_pitch} 不是 0，並且滿足下列條件之一：
\startigBase
\item 小於 \math{\marg{region}[1] * \marg{src_row_pitch}}；
\item 或者不是 \carg{src_row_pitch} 的整數倍。
\stopigBase
\stopitem

\startitem
\cenum{CL_INVALID_VALUE}，如果 \carg{dst_slice_pitch} 不是 0，並且滿足下列條件之一：
\startigBase
\item 小於 \math{\marg{region}[1] * \marg{dst_row_pitch}}；
\item 或者不是 \carg{dst_row_pitch} 的整數倍。
\stopigBase
\stopitem

\item \cenum{CL_INVALID_VALUE}，
如果 \carg{src_buffer} 和 \carg{dst_buffer} 是同一個\cnglo{bufobj}，
且 \carg{src_slice_pitch} 不等於 \carg{dst_slice_pitch}
或者 \carg{src_row_pitch} 不等於 \carg{dst_row_pitch}。

\startitem
\cenum{CL_INVALID_EVENT_WAIT_LIST}，如果滿足下列條件中的任一項：
\startigBase
\item \carg{event_wait_list} 是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} > 0；
\item 或者 \carg{event_wait_list} 不是 \cmacro{NULL}，但 \carg{num_events_in_wait_list} 是 0；
\item 或者 \carg{event_wait_list} 中有無效的事件。
\stopigBase
\stopitem

\item \cenum{CL_MEM_COPY_OVERLAP}，
如果 \carg{src_buffer} 和 \carg{dst_buffer} 是同一個\cnglo{bufobj}或子\cnglo{bufobj}，
且源和目的區域重疊。
或者 \carg{src_buffer} 和 \carg{dst_buffer} 是同一\cnglo{bufobj}的不同子\cnglo{bufobj}，
且他們重疊。
對於怎樣確定源和目的區域重疊，請參考\refappendix{overlap}。

\item \cenum{CL_MISALIGNED_SUB_BUFFER_OFFSET}，
如果 \carg{src_buffer} 是子\cnglo{bufobj}，
且創建此對象時所指定的 \carg{offset} 沒有與 \carg{command_queue} 所關聯\cnglo{device}
的 \cenum{CL_DEVICE_MEM_BASE_ADDR_ALIGN} 對齊。

\item \cenum{CL_MISALIGNED_SUB_BUFFER_OFFSET}，
如果 \carg{dst_buffer} 是子\cnglo{bufobj}，
且創建此對象時所指定的 \carg{offset} 沒有與 \carg{command_queue} 所關聯\cnglo{device}
的 \cenum{CL_DEVICE_MEM_BASE_ADDR_ALIGN} 對齊。

\item \cenum{CL_MEM_OBJECT_ALLOCATION_FAILURE}，
如果為 \carg{src_buffer} 或 \carg{dst_bufer} 分配內存失敗。

\item \cenum{CL_OUT_OF_RESOURCES}，如果\scdevfailres。
\item \cenum{CL_OUT_OF_HOST_MEMORY}，如果\schostfailres。
\stopigBase
